/**
 * 项目名：	Rumba Plan
 * 
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2007，所有权利保留。
 * 
 * 文件名：	OptionMgr.java
 * 模块说明：	
 * 修改历史：
 * 2007-3-15 - lxm - 创建。
 */
package com.hd123.rumba.option;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.type.Type;

import com.hd123.rumba.domain.IDomain;
import com.hd123.rumba.exception.BusinessException;
import com.hd123.rumba.log.EntityLogger;
import com.hd123.rumba.runtime.Manager;
import com.hd123.rumba.runtime.NamingMgr;
import com.hd123.rumba.runtime.OperateContext;
import com.hd123.rumba.user.CUser;
import com.hd123.rumba.user.IUser;
import com.hd123.rumba.util.CollectionMatcher;
import com.hd123.rumba.util.ElementMatcher;
import com.hd123.rumba.util.ObjectUtil;

/**
 * 系统选项 | 管理员 | 实现类
 * 
 * @author lxm
 * 
 */
public class OptionMgr extends Manager implements IOptionMgr {

  public static final String CAPTION_MANAGER = "系统选项管理员";

  public OptionMgr() {
    super();
    this.registryClass(IOptionCollection.class.getName(), OptionCollection.class.getName());
    this.registryClass(IOptionItem.class.getName(), OptionItem.class.getName());
  }

  public IOptionCollection createCollection(IDomain domain, Class optionalClass, IUser user)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(optionalClass, "optionalClass");
    return this.createCollection(domain, optionalClass.getName(), user);
  }

  public IOptionCollection createCollection(IDomain domain, String optionalClassName, IUser user)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(domain, "domain");
    this.checkParameterNotNull(optionalClassName, "optionalClassName");

    IOptionalClassInfo classInfo = getClassInfoMgr().fetchClassInfoByClass(optionalClassName);
    IOptionCollection collection = new OptionCollection();
    collection.setDomain(domain);
    collection.setOptionalClassName(optionalClassName);
    if (user != null
        && COptionalClassInfo.VALUE_INDIVIDUATION_DOMAIN.equals(classInfo.getIndividuation()))
      throw new BusinessException("选项禁止" + CUser.CAPTION_CLASS + "个性化设置(" + optionalClassName
          + ")。");
    collection.setUser(user);
    if (collection.getUser() != null) {
      collection.setLocked(classInfo.getLocked());
      collection.setOnline(classInfo.getOnline());
    }
    collection.setInherited(Boolean.TRUE);
    return collection;
  }

  public IOptionItem createItem(IOptionCollection collection) throws BusinessException {
    this.checkParameterNotNull(collection, "collection");
    IOptionItem item = new OptionItem();
    item.setCollection(collection);
    return item;
  }

  public void addItemToCollection(IOptionCollection collection, IOptionItem item)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(item, "item");

    if (collection.getItems().contains(item))
      return;
    if (item.getCollection() != collection)
      throw new BusinessException("指定被添加的" + COptionItem.CAPTION_CLASS + "不属于指定的"
          + COptionCollection.CAPTION_CLASS + "。");
    if (collection.getItemByName(item.getName()) != null)
      throw new BusinessException("已经存在相同" + COptionItem.CAPTION_NAME + "(" + item.getName() + ")的"
          + COptionItem.CAPTION_CLASS + "。");
    collection.getItems().add(item);
  }

  public void removeItemFromCollection(IOptionCollection collection, IOptionItem item)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(item, "item");

    if (!collection.getItems().contains(item))
      return;

    collection.getItems().remove(item);
    getSession().delete(item);
  }

  public void saveCollection(IOptionCollection collection, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(operate, "operate");

    verifyToSave(collection);

    Date operTime = operate.getTime();
    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(collection);
    logger.setEntityConstClass(COptionCollection.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operTime);

    boolean isNew = collection.getUuid() == null;
    collection.setLastModifier(operate.getOperator().getNameCode());
    collection.setLastModified(operTime);
    getSession().saveOrUpdate(collection);

    if (isNew)
      logger.log(EntityLogger.EVENT_ADDNEW, collection.getState(), null);
    else
      logger.log(EntityLogger.EVENT_MODIFY, collection.getState(), null);
  }

  public void removeCollection(IOptionCollection collection, OperateContext operate)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(collection, "collection");
    this.checkParameterNotNull(operate, "operate");
    Date operTime = operate.getTime();
    EntityLogger logger = new EntityLogger(this);
    logger.setEntity(collection);
    logger.setEntityConstClass(COptionCollection.class);
    logger.setOperator(operate.getOperator());
    logger.setTime(operTime);
    logger.log(EntityLogger.EVENT_REMOVE, collection.getState(), collection.toBizString());
    getSession().delete(collection);
  }

  public void copyItems(IOptionCollection source, IOptionCollection target)
      throws BusinessException, HibernateException {
    ObjectUtil.checkParameterNotNull(source, "source");
    ObjectUtil.checkParameterNotNull(target, "target");

    if (!source.getDomain().getUuid().equals(target.getDomain().getUuid())
        || !source.getOptionalClassName().equals(target.getOptionalClassName()))
      throw new BusinessException("作为源与目的的" + COptionCollection.CAPTION_CLASS + "是非同构的，两者不能复制数据。");
    
    CollectionMatcher<IOptionItem, IOptionItem> cm = new CollectionMatcher(
        new ElementMatcher<IOptionItem, IOptionItem>() {
          public boolean match(IOptionItem a, IOptionItem b) throws Exception{
            return a.getName().equals(b.getName());
          }
        }
    );
    
    try {
      Collection<IOptionItem> delCol = cm.subtractA(target.getItems(), source.getItems());
      for (IOptionItem targetItem : delCol)
        this.removeItemFromCollection(target, targetItem);
      
      Map<IOptionItem, IOptionItem> modCol = cm.multiple(target.getItems(), source.getItems());
      for (IOptionItem targetItem : modCol.keySet()) {
        IOptionItem sourceItem = modCol.get(targetItem);
        targetItem.setValue(sourceItem.getValue());
      }
      
      Collection<IOptionItem> insCol = cm.subtractB(target.getItems(), source.getItems());
      for (IOptionItem sourceItem : insCol) {
        IOptionItem targetItem = this.createItem(target);
        targetItem.setName(sourceItem.getName());
        targetItem.setValue(sourceItem.getValue());
        this.addItemToCollection(target, targetItem);
      }
      
    } catch (Exception e) {
      throw new BusinessException(e);
    }
  }

  public IOptionCollection getCollection(String uuid) throws BusinessException, HibernateException {
    this.checkParameterNotNull(uuid, "uuid");
    return (IOptionCollection) getSession().get(IOptionCollection.class, uuid);
  }

  public IOptionCollection getCollectionByClass(IDomain domain, Class optionalClass, IUser user)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(optionalClass, "optionalClass");
    return this.getCollectionByClass(domain, optionalClass.getName(), user);
  }

  public IOptionCollection getCollectionByClass(IDomain domain, String optionalClassName, IUser user)
      throws BusinessException, HibernateException {
    this.checkParameterNotNull(domain, "domain");
    this.checkParameterNotNull(optionalClassName, "optionalClassName");
    List list = null;
    if (user == null)
      list = getSession().find(
          "from " + IOptionCollection.class.getName() + " oc"
              + " where oc.domain.uuid = ? and oc.optionalClassName = ?" + " and oc.user is null",
          new Object[] {
              domain.getUuid(), optionalClassName }, new Type[] {
              Hibernate.STRING, Hibernate.STRING });
    else
      list = getSession().find(
          "from " + IOptionCollection.class.getName() + " oc"
              + " where oc.domain.uuid = ? and oc.optionalClassName = ?" + " and oc.user.uuid = ?",
          new Object[] {
              domain.getUuid(), optionalClassName, user.getUuid() }, new Type[] {
              Hibernate.STRING, Hibernate.STRING, Hibernate.STRING });
    if (list.size() > 0)
      return (IOptionCollection) list.get(0);
    else
      return null;
  }

  private IOptionalClassInfoMgr classInfoMgr = null;

  private IOptionalClassInfoMgr getClassInfoMgr() throws BusinessException {
    if (classInfoMgr == null)
      classInfoMgr = (IOptionalClassInfoMgr) NamingMgr.getInstance().lookupMgr(
          IOptionalClassInfoMgr.class);
    return classInfoMgr;
  }

  private void verifyToSave(IOptionCollection collection) throws BusinessException,
      HibernateException {
    // 检查个性化级别
    if (collection.getUser() != null) {
      IOptionalClassInfo classInfo = getClassInfoMgr().fetchClassInfoByClass(
          collection.getOptionalClassName());
      if (COptionalClassInfo.VALUE_INDIVIDUATION_DOMAIN.equals(classInfo.getIndividuation()))
        throw new BusinessException("选项禁止" + CUser.CAPTION_CLASS + "个性化设置("
            + collection.getOptionalClassName() + ")。");
    }

    // 检查是否被系统管理员锁定
    if (collection.getUser() != null) {
      IOptionCollection globalCol = this.getCollectionByClass(collection.getDomain(), collection
          .getOptionalClassName(), null);
      if (globalCol == null)
        globalCol = this.createCollection(collection.getDomain(),
            collection.getOptionalClassName(), null);
      if (globalCol.getLocked().booleanValue())
        throw new BusinessException(CUser.CAPTION_CLASS + "个性化设置功能已经被系统管理员锁定，禁止修改。");
    }

    // 检查是否有重复的选项名
    HashMap names = new HashMap();
    for (int i = 0; i < collection.getItems().size(); i++) {
      IOptionItem item = collection.getItems().get(i);
      names.put(item.getName(), null);
    }
    if (names.size() < collection.getItems().size())
      throw new BusinessException("出现重复的" + COptionItem.CAPTION_NAME + "。");
  }
}
